package com.acmen.easyapi.parse;

import com.acmen.easyapi.annotation.Param;
import com.acmen.easyapi.annotation.ReqParam;
import com.acmen.easyapi.generator.DataGenerator;
import com.acmen.easyapi.generator.DataGeneratorFactory;
import com.acmen.easyapi.model.ParamNode;
import com.acmen.easyapi.model.ReqParamNode;
import com.acmen.easyapi.strategy.ReqParamStrategy;
import com.acmen.easyapi.validation.ValidatorNoteAppender;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import com.acmen.easyapi.util.ClassUtil;
import com.acmen.easyapi.util.DictionaryUtil;
import com.acmen.easyapi.util.SpringContextUtil;
import com.acmen.easyapi.util.StringUtil;

import javax.annotation.Resource;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.lang.reflect.Field;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;


/**
 * 请求命令解析器
 * @author acmen
 */
public class BaseRequestParser extends ParamParser {
    @Resource
    private DataGeneratorFactory dataGeneratorFactory;
    @Resource
    private ReqParamStrategy reqParamStrategy;

    @Override
    protected List<ParamNode> createNodesForClass(Class clazz, Map<TypeVariable, Type> typeMap) {
        List<ParamNode> paramNodes = new ArrayList<>();
        if(ClassUtil.isBasicType(clazz)){
            return paramNodes;
        }
        List<Field> fields = ClassUtil.getFields(clazz);
        if (fields.isEmpty()) {
            return paramNodes;
        }
        if(paramNodeMap.containsKey(clazz.getName())){
            //变成新对象
            return (List)JSON.parseArray(JSON.toJSONString(paramNodeMap.get(clazz.getName())), ReqParamNode.class);
        }
               // 遍历fields集合，对每个field进行处理
        for (Field field : fields) {
            // 获取JSONField注解
            JSONField jsonField = ClassUtil.getAnnotation(field, JSONField.class);
            // 如果jsonField不为空且deserialize为false，则跳过当前循环
            if(jsonField!=null&&!jsonField.deserialize()){
                continue;
            }
            // 获取param注解
            Param param = reqParamStrategy.getParam(clazz,field);
            // 如果param为null，则跳过当前循环
            if(param == null){
                continue;
            }
            // 创建ReqParamNode节点
            ReqParamNode paramNode = new ReqParamNode();
            // 设置字段名
            paramNode.setName(field.getName());
            // 设置字段（节点）描述
            paramNode.setLabel(param.label());
            // 判断是否为数组类型，并设置相应的字段属性
            Type fieldType = getTargetType(field.getGenericType(), typeMap);
            if(fieldType!=null){
                paramNode.setArray(isArrayType(fieldType));
            }else{
                paramNode.setArray(isArrayType(field.getType()));
            }
            // 判断是否必需字段，并设置相应的字段属性
            paramNode.setRequired(isRequired(clazz,field));
            // 获取ReqParam注解
            ReqParam reqParam = reqParamStrategy.getReqParam(clazz,field);
            // 如果reqParam不为空，则设置相应的字段属性
            if(reqParam!=null){
                // 设置必需组
                paramNode.setRequiredGroup(reqParam.requiredGroup());
                // 设置校验表达式
                paramNode.setValidateExp(reqParam.validateExp());
                // 设置字符长度限制
                if(reqParam.maxLength()>0){
                    paramNode.setMaxLength(reqParam.maxLength());
                }
                // 设置数字最大限制
                if(reqParam.max()<Long.MAX_VALUE){
                    paramNode.setMax(reqParam.max());
                }
                // 设置数字最小限制
                if(reqParam.min()>-Long.MAX_VALUE){
                    paramNode.setMin(reqParam.min());
                }
            }
            // 设置字段类型
            paramNode.setType(converTypeName(field.getGenericType()));
            // 设置字段类型别名
            String typeAlias = getDataTypeAlias(field.getGenericType(), typeMap);
            paramNode.setTypeAlias(typeAlias);
            // 判断字段是否被标记为弃用，并设置相应的字段属性
            Deprecated deprecated = field.getAnnotation(Deprecated.class);
            if(deprecated!=null){
                paramNode.setDeprecated(true);
            }
            // 如果param的dictType不为空，则设置相应的字段属性
            if(StringUtil.isNotEmpty(param.dictType())){
                paramNode.setDictType(param.dictType());
            }else if (field.getType().isEnum() ) {
                // 如果field的类型是枚举类型，则设置相应的字段属性
                paramNode.setDictionaries(DictionaryUtil.getDictsFromEnum2(field.getType()));
            }else if(param.enumClass().isEnum()){
                // 如果param的enumClass是枚举类型，则设置相应的字段属性
                paramNode.setDictionaries(DictionaryUtil.getDictsFromEnum(param.enumClass()));
            }
            // 设置字段说明
            paramNode.setNotes(getNotes(param));
            // 设置子节点
            if(StringUtil.isNotEmpty(param.example())){
                paramNode.setExample(param.example());
            }else{
                // 如果field和param适用于DataGenerator，则生成随机数据并设置为子节点
                DataGenerator dataGenerator = dataGeneratorFactory.getDataGenerator(field, param);
                if (dataGenerator != null) {
                    Object randomData = dataGenerator.generate(field, param);
                    paramNode.setExample2(randomData);
                }
            }
            // 将paramNode添加到paramNodes集合中
            paramNodes.add(paramNode);
        }

        paramNodeMap.put(clazz.getName(), paramNodes);

              // 遍历fields集合中的每个元素field
        for (Field field : fields) {
            // 通过paramNodes集合过滤出与field的名称相同的ParamNode对象，返回一个Optional对象optional
            Optional<ParamNode> optional = paramNodes.stream().filter(x->StringUtil.equals(x.getName(),field.getName())).findFirst();
            // 如果optional对象不存在，则跳过当前循环
            if(!optional.isPresent()){
                continue;
            }
            // 如果field的类型是基本类型，则跳过当前循环
            if(ClassUtil.isBasicType(field.getClass())){
                continue;
            }
            // 将optional对象获取的ReqParamNode对象强制转换为ReqParamNode类型，并赋值给paramNode变量
            ReqParamNode paramNode = (ReqParamNode)optional.get();
            // 通过typeMap对象和field的GenericType属性创建ParamNode集合subNodes
            List<ParamNode> subNodes = createParamNodes(field.getGenericType(), typeMap);
            // 如果subNodes集合不为空
            if(!subNodes.isEmpty()){
                // 通过subNodes集合过滤出与paramNode的名称相同的ParamNode对象，返回一个Optional对象opt
                Optional<ParamNode> opt = subNodes.stream().filter(x->StringUtil.equals(x.getName(),paramNode.getName())).findFirst();
                // 如果opt对象存在，则将opt获取的ParamNode对象的名称添加"(树)"后缀，并重新赋值给paramNode变量
                if(opt.isPresent()){
                    ParamNode rpn = opt.get();
                    rpn.setName(rpn.getName()+"(树)");
                }
                // 将subNodes赋值给paramNode的subNodes属性
                paramNode.setSubNodes((List)subNodes);
            }
        }

        return paramNodes;
    }

    protected List<String> getNotes(Param param) {
                List<String> notes = new ArrayList<>();  // 创建一个字符串列表来存储注释

        if(StringUtil.isNotEmpty(param.note())){
            notes.add(param.note());  // 如果参数param的note()方法返回的字符串不为空，则将其添加到notes列表中
        }

        if(StringUtil.isNotEmpty(param.validateExp())){
            ValidatorNoteAppender noteAppender = SpringContextUtil.getBean(ValidatorNoteAppender.class);  // 获取ValidatorNoteAppender对象
            if(noteAppender!=null){
                String validateNote = noteAppender.getNote(param.validateExp());  // 调用ValidatorNoteAppender对象的getNote()方法，获取验证注释
                if(StringUtil.isNotEmpty(validateNote)){
                    notes.add(validateNote);  // 如果验证注释不为空，则将其添加到notes列表中
                }
            }
        }
        return notes;
    }

    /**
     * 检查字段值是否必填
     * @param field
     * @return
     */
    private boolean isRequired(Class clazz,Field field){
               // 根据给定的类和字段获取请求参数
        ReqParam reqParam = reqParamStrategy.getReqParam(clazz, field);

        // 如果请求参数不为空且必须，则返回true
        if (reqParam != null && reqParam.required()) {
            return true;
        }

        // 如果字段上存在@NotNull注解，则返回true
        NotNull notNull = ClassUtil.getAnnotation(field, NotNull.class);
        if (notNull != null) {
            return true;
        }

        // 如果字段上存在@NotEmpty注解，则返回true
        NotEmpty notEmpty = ClassUtil.getAnnotation(field, NotEmpty.class);
        if (notEmpty != null) {
            return true;
        }

        // 如果字段上存在@NotBlank注解，则返回true
        NotBlank notBlank = ClassUtil.getAnnotation(field, NotBlank.class);
        if (notBlank != null) {
            return true;
        }

        // 否则返回false
        return false;

    }
}
